<?php
/**
 * 宝石城堡
 */

namespace App\Repositories\Game\Castle;

use App\Models\GameDB\Castle\CastleBetLog;
use App\Models\GameDB\Castle\CastleDrawLog;
use App\Models\GameDB\Castle\CastleGift;
use App\Models\GameDB\Castle\CastleTotal;
use App\Models\GameDB\Castle\CastleUser;
use App\Models\GameDB\Castle\CastleUserExchangeGift;
use App\Models\GameDB\Castle\CastleUserExchangeLog;
use App\Models\MainDB\User;
use App\Models\MainDB\UserData;
use App\Repositories\LogRepository;
use App\Services\RedisServices;
use App\Services\Tools\RedisService;
use App\Traits\Singleton;
use App\Models\MainDB\AccountLog;
use App\Exceptions\BasicException;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use App\Repositories\UserRepository;
use PhpParser\Node\Stmt\TryCatch;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use function Swoole\Coroutine\map;

class CastleRepositories
{
    use Singleton;

    /**
     * @param int $userId
     * @param int $number
     * 兑换 宝石城堡币
     * @return array
     * @throws BasicException
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * @throws \Exception
     */

    public function exchange(int $userId, int $number)
    {
        //原先的逻辑   判断用户id不能为空
        if (empty($userId)) {
            throw new BasicException(-1, '非法请求');
        }
        //获取当前用户的金币信息，游戏信息
        //拉取本局游戏配置
        //为用户数据添加宝石，用户数据在game_result消息中初始
//        if(!in_array($number, explode(',',$setting->setting))){
//            throw new BasicException(-1, "非法请求");
//        }

        DB::beginTransaction();
        DB::connection("mysql_game")->beginTransaction();
        try {     // 验证金币
            $setting = CastleSettingRepository::getInstance()->setting(true);
            $coin = $setting['exchange'] * $number;
            $userCoin = User::query()->lockForUpdate()->where("user_id", $userId)->value("money");
            if ($coin > $userCoin) { // 金币不足
                throw new BasicException(340001, "金币不足");
            }
            // 增加余额日志
            $log = CastleExchangeLogRepositories::getInstance()->swap($userId, $number, $userCoin, $coin);
            // 增加余额
            CastleUserRepositories::getInstance()->swap($userId, $number);
            // 钱包服务
            UserRepository::getInstance()->decUserMoney($userId, $coin);
            app('model_account_log')->addLog($userId, $coin, "兑换飞船 x{$number}", AccountLog::LUCKY_CASTLE, $log->id);
            DB::commit();
            DB::connection("mysql_game")->commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            DB::connection("mysql_game")->rollBack();
            throw new BasicException((int)$e->getCode(), $e->getMessage());
        }
        return [
            'coin' => User::query()->where("user_id", $userId)->value("money") ?? 0,
            'coin_candy' => CastleUser::query()->where("user_id", $userId)->value('coin_candy') ?? 0
        ];
    }

    /**
     * @return false|string[]
     * @throws BasicException
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     * 获取兑换列表
     */
    public function exchangeList()
    {
        $setting = CastleSettingRepository::getInstance()->setting(true);
        return [
            'list' => explode(',', $setting['exchange_list']),
            'exchange' => $setting['exchange']
        ];
    }

    /**
     * 礼物列表
     * @return array
     * @throws BasicException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function giftList($userId)
    {
        // 写缓存代写
        $setting = CastleSettingRepository::getInstance()->setting(true);
        $redis = app('redis');
        $time_status = 1;
        // 获取当前开启的 流水号 id
        $key = 'castle:log:sn';
        if (!app('redis')->exists($key)) {
            $time_status = 2;
        }
        $castleId = app('redis')->get($key);
        // 判断倒计时
        $key2 = 'castle:log:betting' . $castleId;
        $time = app('redis')->get($key2) ?? 0;
        if ($time <= ($setting['exit_time'] + $setting['show_time']) && $time > $setting['exit_time']) {
            $time_status = 3;
        }
        $time = app('redis')->get($key2) ?? 0;
        if($time > 0 && $time <= $setting['exit_time']) {
            $time_status = 2;
        }
        $time = app('redis')->get($key2) ?? 0;
        $time_end = $setting['exit_time'] + $setting['show_time'];
        if ($time - $time_end > 0) {
            $time_status = 1;
        }

        $sum_count = 0;
        $key = 'castle:gift_info';
        if (!$redis->exists($key)) {
            $gift_info = [];
            $gift = [];
            for ($i = 1; $i <= $setting['init_count']; $i++) {
                $gift_id = explode(',', $setting['init_item' . $i]) ?? [];
                if (empty($gift_id)) {
                    continue;
                }
                $gift_find = CastleGift::query()
                    ->where('type', CastleGift::Castle)
                    ->where('id', $gift_id[0])
                    ->select(['id', 'name', 'picture', 'chance', 'weight'])
                    ->first();
                $gift_find['times'] = $gift_id[1];
                $gift_find['count'] = 0;
                $gift_find['lattice'] = $i;
                $gift [] = $gift_find;
                $gift_info[$gift_id[0]] = json_encode($gift_find, true);
            }
            ksort($gift_info);
            arsort($gift_info);
//            usort($gift_info, function ($a, $b) {
//                return $a['lattice'] - $b['lattice'];
//            });
//            collect($gift_info)->sortBy('lattice')->toArray();
//            collect($gift_info)->sortByDesc('lattice')->toArray();
//            array_multisort(array_column($gift_info, 'lattice'), SORT_DESC, $gift_info);
            $redis->lpush($key, $gift_info);
        } else {
            $gift_info = $redis->lrange($key, 0, -1);
            $gift = [];
            foreach ($gift_info as $value) {
                $gift_value = json_decode($value, true);
                // 用户当前的 是否在押注中 在的话就行 查询 那个礼物id 押注过 进行 匹配count
                if ($time_status == 1) {
                    $gift_key = 'castle:gift:stake:user:' . $castleId . ':' . $gift_value['id'];
                    $gift_value['count'] = $redis->zscore($gift_key, $userId) ?? 0;
                    $sum_count += $gift_value['count'];
                }
                $gift [] = $gift_value;
            }
        }
        $bet_count = explode(',', $setting['bet_count']);
        $bet_count = empty($bet_count) ? [1, 10, 100] : $bet_count;
        return [
            'gift' => $gift,
            'sum' => $sum_count,
            'bet_count' => $bet_count,
            'content' => $setting['content'],
            'time_status' => $time_status
        ];
    }

    /**
     * 礼物用户信息
     * @param $uid
     * @return Builder|\Illuminate\Database\Eloquent\Model|object|null
     */
    public function userInfo($uid)
    {
        return CastleUser::query()->where('user_id', $uid)
            ->select([
                'coin_candy', 'coin_castle', 'user_id'
            ])
            ->first();
    }

    /**
     * @param int $uid
     * 可以不为空
     * @return Builder[]|\Illuminate\Database\Eloquent\Collection
     */
    public function logList($perPage = 8, $uid = '')
    {

        return (new CastleDrawLog)->Log($perPage);
    }

    /**
     *   * 用户押宝
     * @param $uid
     * @param $params
     * @return array
     * @throws BasicException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \Exception
     */
    public function gameBet($uid, $params)
    {
        $number = $params['number'];
        $gift_id = $params['gift_id'];
        // 获取当前开始轮次的ID
        $key = 'castle:log:sn';
        if (!app('redis')->exists($key)) {
            throw new BasicException(-1, '当前轮已结束,请等待下一轮');
        }
        // 获取配置
        $setting = CastleSettingRepository::getInstance()->setting(true);
        // 是否开启状态
        if (!$setting['is_open']) {
            throw new BasicException(-1, '游戏还未开启请等待!');
        }
        if ($setting['is_open_user']) {
            $is_open_user_id = explode(',', $setting['is_open_userId']);
            if (!in_array($uid, $is_open_user_id)) {
                throw new BasicException(-1, '游戏还未开启请等待!!!');
            }
        }
        $castleId = app('redis')->get($key);
        // 判断倒计时
        $key2 = 'castle:log:betting' . $castleId;
        $time = app('redis')->get($key2) ?? 0;
        if ($setting['show_time'] <= $time && $time <= $setting['exit_time'] + $setting['show_time']) {
            throw new BasicException(-1, '本轮正在结算,请等待下一次投票');
        }
        if ($setting['show_time'] > $time) {
            throw new BasicException(-1, '已结算,正在打扫战场,请等待下一次投票');
        }
        $type = $params['type'];
//        $time = app('redis')->get($key2);
        // 获取总配置
        $setting = CastleSettingRepository::getInstance()->setting(true);
        if ($setting['is_open'] != '1') {
            throw new BasicException(-1, '暂未开启');
        }
        $bet_count = explode(',', $setting['bet_count']);
        $bet_count = empty($bet_count) ? [1, 10, 100] : $bet_count;
        if (!in_array($number, $bet_count)) {
            throw new BasicException(-1, '非法请求');
        }

        $user_info = CastleUser::query()->where('user_id', $uid)->lockForUpdate()->first();
        if ($user_info['coin_candy'] < $number && $type == 1) {
            throw new BasicException(-1, '飞船不足!请兑换');
        }

//        // 判断 是否在选购阶段
//        if ($setting['sum_time'] - $time > $setting['bet_time']) {
//            throw new BasicException(-1, '本轮次正在结算,请等待下一轮');
//        }

        $gift_array = $params['gift_info'] ?? [];
        if (empty($gift_array)) {
            // 就报错
            throw new BasicException(-1, '用户投票异常');
        }
        // 进行判断 用户金额是否足够
        // 获取礼物的
        $lattice = $params['lattice'];
        $gift_info = app('redis')->lindex('castle:gift_info', $lattice - 1);
        if (!$gift_info) {
            $gift_info_new = [];
            $gift_find_new = [];
            for ($i = 1; $i <= $setting['init_count']; $i++) {
                $gift_id_new = explode(',', $setting['init_item' . $i]) ?? [];
                if (empty($gift_id_new)) {
                    continue;
                }
                $gift_find = CastleGift::query()
                    ->where('type', CastleGift::Castle)
                    ->where('id', $gift_id_new[0])
                    ->select(['id', 'name', 'picture', 'chance', 'weight'])
                    ->first();
                $gift_find['times'] = $gift_id_new[1];
                $gift_find['count'] = 0;
                $gift_find['lattice'] = $i;
                if($i == $lattice){
                    $gift_find_new = $gift_find;
                }
                $gift_info_new[$gift_id_new[0]] = json_encode($gift_find, true);
            }
            ksort($gift_info_new);
            arsort($gift_info_new);
            app('redis')->lpush('castle:gift_info', $gift_info_new);
            $gift_info = $gift_find_new;
        }else{
            $gift_info = json_decode($gift_info, true);
        }
        if(empty($gift_info)) throw new BasicException(-1, '操作太快了,歇歇再点击吧');
        // 判断当前 礼物和 格子是否能对上
        if ($gift_info['id'] != $gift_id) {
            throw new BasicException(-1, '星球和格子信息对不上!');
        }
        // 获取礼物信息
        // 上锁
        $coin = $number * $setting['exchange'];
        $hasLock = RedisService::addCastleLock($uid);
        if (!$hasLock) {
            throw new BasicException(-1, '操作太快了,歇歇再点击吧');
        }
        //
        DB::beginTransaction();
        try {
//            $logRtx = new LogRepository("111111111111111111");
//            $logRtx->log(date("Y-m-d H:i:s"),'');
            // 处理逻辑
            // 更新表格
            $gift_info_new = RedisService::getCastleUser($castleId, $uid, $gift_array, $gift_id, $number, $lattice, $type, $setting['sum_time']);
            // 存押注的用户
            $time = date('Ymd');
            $bet_user_count = RedisService::getCastleStakeUser($castleId, $uid, $time, $setting['sum_time']);
            // 添加当前的流水线
            $bet_slot_count = "bet_slot_count" . $lattice;
            if ($type == 1) {
                // 扣币
                $coin_candy = $user_info['coin_candy'] - $number;
                CastleUserRepositories::getInstance()->decrement($uid, $number);
                CastleDrawLog::query()->where('id', $castleId)
                    ->update([
                        "bet_user_count" => $bet_user_count,
                        "$bet_slot_count" => DB::raw("`$bet_slot_count` + $number"),
                        "bet_total_gold" => DB::raw("`bet_total_gold` + $coin")
                    ]);
            } else {
                // 回币  // 先进行 查询 缓存是否已经归  0
                $coin_candy = $user_info['coin_candy'] + $number;
                CastleUserRepositories::getInstance()->increment($uid, $number);
                CastleDrawLog::query()->where('id', $castleId)
                    ->update([
                        "bet_user_count" => $bet_user_count,
                        "$bet_slot_count" => DB::raw("`$bet_slot_count` - $number"),
                        "bet_total_gold" => DB::raw("`bet_total_gold` - $coin")
                    ]);
            }
            // 押宝记录 一个就生成一条  redis 存数组  待整改  要是添加就更新
            $CastleBetLog = new CastleBetLog();
            $find = $CastleBetLog::query()->where([
                'user_id' => $uid,
                'draw_id' => $castleId
            ])->first();
            // {"1":2,"3":1}
            if ($find) {
                // 如果 金额变0  就直接删掉redis的数据
                $cost_gold = $type == 1 ? $find['cost_gold'] + $number * $setting['exchange'] : $find['cost_gold'] - $number * $setting['exchange'];
                $is_deposit = $cost_gold <= 0 ? 0 : 1;
                if (!$is_deposit) {
                    RedisService::getCastleStakeUser($castleId, $uid, $time, $setting['sum_time'], true);
                }
                // 删除掉redis 数据
                $find->update([
                    'memo' => $type == 1 ? $find['memo'] . ',' . date('Y-m-d H:i:s') . ' ' . "下注 $lattice 号格子,礼物id为" . $gift_info['id'] . ",礼物名称" . $gift_info['name'] . "下注数量X" . $number : $find['memo'] . ',' . date('Y-m-d H:i:s') . ' ' . "用户取消下注 $lattice 号格子,礼物id为" . $gift_info['id'] . ",礼物名称" . $gift_info['name'] . "下注数量X" . $number,
                    'info' => json_encode($gift_info_new, true),
                    'remain_candy' => $coin_candy,
                    'cost_gold' => $cost_gold,
                    'is_deposit' => $is_deposit
                ]);
            } else {
                $CastleBetLog->user_id = $uid;
                $CastleBetLog->round = $castleId;   // 所有格子下注详情  去redis
                $CastleBetLog->draw_id = $castleId;   // 所有格子下注详情  去redis
                $CastleBetLog->memo = date('Y-m-d H:i:s') . ' ' . "下注 $lattice 号格子,礼物id为" . $gift_info['id'] . ",礼物名称" . $gift_info['name'] . "下注数量X" . $number;   // 所有格子下注详情  去redis
                $CastleBetLog->info = json_encode($gift_info_new, true);   // 所有格子下注详情  取 redis
                $CastleBetLog->remain_candy = $coin_candy;
                $CastleBetLog->create_time = date('Y-m-d H:i:s');
                $CastleBetLog->cost_gold = $number * $setting['exchange'];
//                $CastleBetLog->is_deposit = $is_deposit;
                $CastleBetLog->save();
            }
            // 记录用户下载参数  redis
            DB::commit();
        } catch (\Throwable $e) {
            RedisService::unLockCastleLock($uid, $hasLock);
            DB::rollBack();
            throw new BasicException(-1, $e->getMessage());
        }
        RedisService::unLockCastleLock($uid, $hasLock);
        return [
            'gift_info_new' => $this->giftInfoArray($gift_info_new),
            'coin_candy' => $coin_candy,
            'sum' => intval(RedisService::getCastleStakeUserCount($castleId, $uid, $number, $type, $setting['sum_time'])) ?? 0
        ];
    }

    /**
     * @param $gift_info_new
     * @return array
     * 获取礼物列表转化
     */
    public function giftInfoArray($gift_info_new)
    {
        $data = [];
        foreach ($gift_info_new as $val) {
            $data[] = json_decode($val) ?? [];
        }
        return $data;
    }

    public function gameResult($userId, $type, $day = false, $page = 1, $perPage = 10)
    {
        if ($type == 1) {
            // 记录
            $yesterday = date('Y-m-d 00:00:00', strtotime("-1 day")); // 计算昨天的日期
            $yesterdayEnd = date('Y-m-d 00:00:00'); // 计算昨天的日期
            $my_field = ['gift.name', 'gift.picture', 'log.id as draw_id', 'ln_game_castle_bet_log.user_id', 'log.round', 'log.end_time', 'ln_game_castle_bet_log.info', 'ln_game_castle_bet_log.is_draw', 'ln_game_castle_bet_log.give_gold'];
            $myInfo = CastleBetLog::query()
                ->leftJoin('ln_game_castle_draw_log as log', 'ln_game_castle_bet_log.draw_id', '=', 'log.id')
                ->leftJoin('ln_game_castle_gift as gift', 'log.draw_item_id', '=', 'gift.id')
                ->where('ln_game_castle_bet_log.user_id', $userId)
                ->where('ln_game_castle_bet_log.cost_gold', '>', 0)
                ->where('log.is_draw', 1);
            if ($day) {
                $myInfo = $myInfo->whereBetween('ln_game_castle_bet_log.created_at', [$yesterday, $yesterdayEnd]);
            }
            $myInfo = $myInfo->orderBy('log.id', 'desc')->paginate($perPage, $my_field, 'page', $page)->toArray();
            // 后期直接在押宝存数据 和存缓存 不直接读库
            $myInfo['data'] = array_map(function ($val) {
                $ya_info = json_decode($val['info'], true);
                if (!empty($ya_info)) {
                    $draw_info = '选择了：';
                    foreach ($ya_info as $v) {
                        $v_data = json_decode($v, true);
                        if ($v_data['count'] > 0) {
                            $draw_info .= $v_data['name'] . 'X' . $v_data['count'] . ',';
                        }
                    }
                    $val['draw_info'] = $draw_info;
                }
                $val['give_gold'] = $val['give_gold'] * 0.01;
                return $val;
            }, $myInfo['data']);
            return $myInfo;
        } else {
            // 是否昨天的分页
            $yesterday = date('Y-m-d 00:00:00', strtotime("-1 day")); // 计算昨天的日期
            $yesterdayEnd = date('Y-m-d 00:00:00'); // 计算昨天的日期
            $query = CastleDrawLog::query()
                ->leftJoin('ln_game_castle_gift as gift', 'ln_game_castle_draw_log.draw_item_id', '=', 'gift.id')
                ->where('ln_game_castle_draw_log.is_draw', 1);
            if ($day) {
                $query = $query->whereBetween('start_time', [$yesterday, $yesterdayEnd]);
            }
            $field = ['gift.id as gift_id', 'gift.name', 'gift.picture', 'ln_game_castle_draw_log.id as draw_id', 'ln_game_castle_draw_log.round', 'ln_game_castle_draw_log.end_time'];
            return $query->orderBy('ln_game_castle_draw_log.id', 'desc')->paginate($perPage, $field, 'page', $page);
        }
    }

    /**
     * @param $userId
     * @param $type
     * @param int $page
     * @param int $perPage
     * 中奖次数 含日榜，周榜，月榜，总榜
     * @return array
     * @throws BasicException
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public function drawRank($userId, $type = 1, $page = 1, $perPage = 10)
    {
        // 取redis  数据 获取  30 秒
        $redisCacheKey = "castle:ranking:list:$type:$page:$perPage";
        // 是否有缓存 有的话就直接上去  存缓存

        switch ($type) {
            case 1 :
                $day = date('Ymd');
                $value = 'day';
                break;
            case 2 :
                $day = date('Ymd', strtotime('-1 day'));
                $value = 'day';
                break;
            case 3 :
                $day = date('Ymd', strtotime('monday this week'));
                $value = 'week';
                break;
            case 4 :
                $day = date('Ymd', strtotime('last monday'));
                $value = 'week';
                break;
            case 5 :
                $day = date('Ym01');
                $value = 'month';
                break;
            case 6 :
//                throw new BasicException(-1, '暂无总榜');
                $day = '2024';
                $value = 'total';
                break;
            default:
                throw new BasicException(-1, '暂无操作!');
        }

        $Key = 'castle:list:ranking:' . $value . ':' . $day;

        if (app("redis")->exists($redisCacheKey)) {
            $cacheData = app("redis")->get($redisCacheKey);
            $list = empty($cacheData) ? [] : json_decode($cacheData, true);
            return [
                'list' => $list,
                'my' => self::oneRanking($Key, $userId),
            ];
        }
//
//
//        if ($dayIs) {
//            // 昨天  上周  上月
//            $day = date('Ymd', strtotime('-1 day')); // 计算昨天的日期
//            $week = date('Ymd', strtotime('last monday')); // 计算昨天的日期
//            $month = date('Ym01', strtotime("first day of last month")); // 计算昨天的日期  去缓存 和 存缓存
//            $dayKey = 'castle:list:ranking:day:' . $day;
//            $weekKey = 'castle:list:ranking:week:' . $week;
//            $monthKey = 'castle:list:ranking:month:' . $month;
//        } else {
//            // 今天
//            $day = date('Ymd'); // 计算昨天的日期
//            // 本周
//            $week = date('Ymd', strtotime('monday this week')); // 计算昨天的日期
//            // 本月
//            $month = date('Ym01'); // 计算昨天的日期  去缓存 和 存缓存
//            $dayKey = 'castle:list:ranking:day:' . $day;
//            $weekKey = 'castle:list:ranking:week:' . $week;
//            $monthKey = 'castle:list:ranking:month:' . $month;
//        }
//        $data = [
//            'day' => [
//                'totalInfo' => self::totalRanking($dayKey, $page, $perPage),
//                'myRanking' => self::oneRanking($dayKey, $userId)
//            ],
//            'week' => [
//                'totalInfo' => self::totalRanking($weekKey, $page, $perPage),
//                'myRanking' => self::oneRanking($weekKey, $userId)
//            ],
//            'month' => [
//                'totalInfo' => self::totalRanking($monthKey, $page, $perPage),
//                'myRanking' => self::oneRanking($monthKey, $userId)
//            ],
//        ];
        $list = self::totalRanking($Key, $page, $perPage);
        $data = [
            'list' => $list,
            'my' => self::oneRanking($Key, $userId),
        ];
        app("redis")->setex($redisCacheKey, 10, json_encode($list));
        return $data;
    }

    /**
     * 计算offset
     * @param $page
     * @param $limit
     * @return mixed
     */
    public static function getOffset($page, $limit)
    {
        return ($page - 1) * $limit;
    }

    public static function totalRanking($key, $page = 1, $perPage = 10)
    {
        $ranking_data = app('redis')->zrevrange($key, 0, -1, "WITHSCORES");
        // 获取所有成员
        $user_ids = array_reverse(app('redis')->zrange($key, 0, -1) ?? []);

        // 不按照 $user_ids 来查询
        $data = UserData::query()->whereIn('user_id', $user_ids)
            ->select(['user_id', 'nickname', 'head_picture'])
            ->orderBy(DB::raw('FIND_IN_SET(user_id, "' . implode(",", $user_ids) . '"' . ")"))
            ->paginate($perPage)->toArray();
        $index = self::getOffset($page, $perPage);
        $data['data'] = array_map(function ($val) use (&$index, $ranking_data) {
            $val['count'] = $ranking_data[$val['user_id']];
            $val['ranking'] = ++$index;
            return $val;
        }, $data['data']);
        return $data;
    }

    /**
     * @param $key
     * @param $userId
     * @return mixed
     * 获取用户排名
     */
    public static function oneRanking($key, $userId)
    {
        $rank = app('redis')->zrevrank($key, $userId);
        $ranking = is_null($rank) ? 0 : $rank + 1; // 获取用户排名（从高到低）
        $userInfo = UserData::query()->where('user_id', $userId)->select(['user_id', 'nickname', 'head_picture'])->first();
        $userInfo['ranking'] = $ranking;
        $userInfo['count'] = app('redis')->zscore($key, $userId);
        return $userInfo;
    }

//    /**
//     * @param $time  弃用
//     * @param $perPage
//     * @return array|\Illuminate\Contracts\Pagination\LengthAwarePaginator
//     */
//    public static function totalRanking($time, $perPage)
//    {
//        $CastleTotal = new CastleTotal();
//        $CastleTotal = $CastleTotal->query()
//            ->leftJoin('main.ln_user_data as user', 'ln_game_castle_total.user_id', '=', 'user.user_id');
//        $info = $CastleTotal
//            ->where('ln_game_castle_total.date', '>=', $time)
//            ->select(['ln_game_castle_total.user_id', DB::raw('sum(count) as totalCount')])
//            ->groupBy('ln_game_castle_total.user_id')->orderBy('totalCount', 'desc')->paginate($perPage);
//        return $info ?? [];
//    }
//
//    /**
//     * @param $time  弃用
//     * @param $userId
//     * @return array
//     */
//    public static function oneRanking($time,$userId){
//        // 当前自己的排名   大于当前自己的排名的 count  太卡了 直接上 开奖上缓存 直接去缓存 和存数据  存 有序集合
//        $model = new CastleTotal();
//        $model =  $model->query()->leftJoin('main.ln_user_data as user', 'ln_game_castle_total.user_id', '=', 'user.user_id')
//            ->where('ln_game_castle_total.date', '>=', $time);
//
//        $info = $model
//            ->where('ln_game_castle_total.user_id',$userId)
//            ->select(['ln_game_castle_total.user_id', DB::raw('sum(count) as totalCount')])
//            ->groupBy('ln_game_castle_total.user_id')
//            ->first();
//        if(empty($info)){
//            return [];
//        }
//         $my_rank = $model->select(['ln_game_castle_total.user_id', DB::raw('sum(count) as totalCount')])
//             ->where('totalCount' , '>=' , $info['totalCount'])
//             ->groupBy('ln_game_castle_total.user_id')
//             ->count();
//         return [];
//    }

    /**
     * @param $userId
     * @param int $type
     * @param int $page
     * @param int $perPage
     * @return array|\Illuminate\Contracts\Pagination\LengthAwarePaginator|Builder|\Illuminate\Database\Query\Builder|mixed
     */
    public function drawLog($userId, $type = 1, $page = 1, $perPage = 10)
    {
        try {
            // 获取最近的中奖记录
            $key = "castle:draw:log:" . $type;
            if ($type == 2) {
                if (app('redis')->exists($key)) {
                    return json_decode(app('redis')->get($key), true) ?? [];
                }
            }
            // 前 50 条记录缓存
            $field = ['ln_game_castle_bet_log.draw_time', 'ln_game_castle_bet_log.give_castle', 'user.user_id', 'user.nickname', 'user.head_picture'];
            $model = CastleBetLog::query()
                ->leftJoin('main.ln_user_data as user', 'ln_game_castle_bet_log.user_id', '=', 'user.user_id')
                ->where('ln_game_castle_bet_log.is_draw', 1);
            if ($type == 1) {
                $model = $model->where('ln_game_castle_bet_log.user_id', $userId);
            }
            // 获取 押宝记录
            $setting = json_decode(app('redis')->get('castle:setting')) ?? [];
            if (empty($setting)) return [];
            if ($type == 2) {
                $model = $model->where('ln_game_castle_bet_log.give_castle', '>=', $setting->broadcast_count);
            }
            $model = $model->orderByDesc('ln_game_castle_bet_log.id')->paginate($perPage, $field, '', $page);
            if ($type == 2) {
                app('redis')->set($key, json_encode($model), 'EX', 10);
            }
            return $model;
        } catch (\Throwable $e) {
            print_r($e->getMessage() . $e->getLine());
        }
    }

    /**
     * @param int $page
     * @param int $perPage
     * @return array
     */
    public function shopItem(int $uid, $page = 1, $perPage = 10)
    {
        // CastleUserExchangeGift  和 gift  考虑 缓存 一下  就不要分页了
        $field = ['a.id as shop_id', 'a.gift_id', 'a.inventory', 'a.price', 'b.name', 'b.picture', 'b.cardiac'];
        $CastleUserExchangeGift = new CastleUserExchangeGift();
        $data = $CastleUserExchangeGift::query()->from("ln_game_castle_user_exchange_gift as a")
            ->leftJoin('main.ln_gift as b', 'a.gift_id', '=', 'b.id')
            ->where('a.sold', '=', 1)->paginate($perPage, $field, '', $page)->toArray();
        $data = array_map(function ($val) use ($uid) {
            // 修改当前的可兑换的 礼物数量
            $where = [
                'user_id' => $uid,
                'gift_id' => $val['gift_id']
            ];
            $inventory_count = CastleUserExchangeLog::query()->where($where)->count() ?? 0;
            $val['inventory'] = $val['inventory'] - $inventory_count;
            return $val;
        }, $data['data']);
        return $data;
    }

    /**
     * @param int $uid
     * @param array $params
     * 兑换礼物
     * @return bool
     * @throws \Exception
     */
    public function shopBuy(int $uid, array $params)
    {
        /*
         * 检查 当前用户的 id 余额不为空
         * 上锁  开启事务
         * 加入兑换记录  扣除 用户的碎片 加入用户背包
         * 关锁 关闭事务
         */
        $key = "castle:shop:buy:" . $uid;
        $gift_id = $params['gift_id'];
        $number = $params['number'];
        $res = app("redis")->set($key, time(), 'ex', 5, 'nx');
        if (!$res) {
            throw new BasicException(-1, "操作太频繁，请稍后再试");
        }
        DB::beginTransaction();
        try {
            $whereGift = [
                'gift_id' => $gift_id,
                'id' => $params['shop_id']
            ];
            $where = [
                'user_id' => $uid,
                'gift_id' => $gift_id
            ];
            $gift_info = CastleUserExchangeGift::query()->where($whereGift)->first();
            if (!$gift_info['sold']) {
                throw new BasicException(10, "礼物未上架");
            }
            $CastleUser = new CastleUser;
            $user = $CastleUser::query()->where('user_id', $uid);
            $coin_castle = $user->value('coin_castle');
            $sum_price = $number * $gift_info['price'];
            if (!$coin_castle || $coin_castle <= 0 || $coin_castle < $sum_price) {
                throw new BasicException(10, "兑换宇宙晶不足");
            }
            $CastleUserExchangeLog = new CastleUserExchangeLog();
            $inventory_count = $CastleUserExchangeLog::query()->where($where)->count();
            // 兑换次数是否大于当前的兑换次数
            if ($inventory_count >= $gift_info['inventory']) {
                throw new BasicException(10, "兑换次数已上限");
            }
            // 减少碎片
            $user->decrement('coin_castle', $sum_price);

            $CastleUserExchangeLog->gift_id = $gift_info['gift_id'];
            $CastleUserExchangeLog->exchange_gift_id = $gift_info['id'];
            $CastleUserExchangeLog->user_id = $uid;
            $CastleUserExchangeLog->residue_coin = $coin_castle - $number * $gift_info['price'];
            $CastleUserExchangeLog->exchange_coin = $number * $gift_info['price'];
            $CastleUserExchangeLog->front_coin = $coin_castle;
            $CastleUserExchangeLog->number = $number;
            $CastleUserExchangeLog->created_at = date('Y-m-d H:i:s');
            $CastleUserExchangeLog->save();
            $user = app("model_user_data")->where("user_id", $uid)->first();
            if (!$user) {
                throw new BasicException(10, "用户不存在！");
            }
            $gift = app('model_gift')->where('id', $gift_id)->first();
            if (!$gift) {
                throw new BasicException(10, '礼物不存在');
            }

//            $where[] = ['user_id', "=", $uid];
//            $where[] = ['gift_id', "=", $gift_id];
            if (app("model_gift_backpack")->where($where)->first()) {
                app("model_gift_backpack")->where($where)->increment('number', $number);
            } else {
                app("model_gift_backpack")->create([
                    'user_id' => $uid,
                    'gift_id' => $gift_id,
                    'number' => $number,
                ]);
            }
            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            app("redis")->del($key);
//            throw new BasicException(-1, $e->getMessage());
            $msg = $e->getCode() == 10 ? $e->getMessage() : "兑换失败!";
            throw new BasicException(-1, $msg);
        }
        app("redis")->del($key);

        return CastleUser::query()->where("user_id", $uid)->value('coin_castle') ?? 0;

        return "兑换成功";

    }


}
